<?
    final class PrvController extends PrincipioLab_Controller_Action
    {
        private static $config_array;
        private static $config_item_value;
        private static $config_last_item;

        private static function start_element ($parser, $name, $attrs)
        {
            self::$config_array[$name] = $attrs;
            self::$config_item_value = "";
        }


        private static function end_element ($parser, $name)
        {
            self::$config_array[$name]['attribute_value'] = self::$config_item_value;
        }


        private static function string_element ($parser, $str)
        {
            if ($str == "&")
            {
                self::$config_item_value .= $str;
                self::$config_last_item = "1";
            }
            else
            {
                if (self::$config_last_item == "1")
                {
                    self::$config_item_value .= $str;
                    self::$config_last_item = "";
                }
                else
                    self::$config_item_value = $str;
            };
        }


        private function make_config_item ($item_name, $item_group, $item_value, $item_ua = "na")
        {
            return "<".$item_name." ".($item_group != "" ? "group=\"".$item_group."\"" : "")." UA=\"".$item_ua."\" >".$item_value."</".$item_name.">\n";
        }


        private function addTemplates(Principio_Model_Templatable $model_templatable)
        {
            $config = "";

            foreach ($model_templatable->getTemplates() as $model_template)
                $config .= $model_template->getTemplate();

            return $config;
        }


        private function addCompanyTemplates(Principio_Model_Spa $model_spa, Principio_Model_Company $model_company_abstract)
        {
            $config = "";

            $config .= $model_company_abstract->getGlobalTemplate();

            for ($i = 1; $i <= $model_spa->getModelType()->getExts(); $i++)
                $config .= preg_replace("/_i/", "_".$i, $model_company_abstract->getExtTemplate());

            if ($model_company_abstract->isCompanyInPool())
                $config .= $this->addCompanyTemplates($model_spa, $model_company_abstract->getModelPool());

            return $config;
        }


        private function gen_config(Principio_Model_Spa $model_spa, $stage, $opa_test)
        {
            global $select_fails_msg;

            switch ($stage)
            {
                case 1: // Main Profile
                    $config = "<flat-profile>\n";

                    if (!$opa_test)
                        Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_ATTEMPT);


                    // Profile

                    // 1. Global Template
                    $config .= Principio_Model_SettingMapper::fetch(Principio_Model_SettingMapper::SETTING_GLOBAL_TEMPLATE_GLOBAL)->getValue();

                    // 2. Extension Template
                    $tmp = Principio_Model_SettingMapper::fetch(Principio_Model_SettingMapper::SETTING_GLOBAL_TEMPLATE_EXT)->getValue();
                    for ($i = 1; $i <= $model_spa->getModelType()->getExts(); $i++)
                        $config .= preg_replace("/_i/", "_".$i, $tmp);

                    // Load all options
                    foreach (Principio_Model_OptionMapper::fetchAll() as $model_option)
                        $config .= $this->make_config_item($model_option->getName(), $model_option->getGroup(), $model_option->getValue());

                    // Firmware
                    if ($model_spa->getModelType()->getModelFirmware()->getID() == -1)
                        $config .= $this->make_config_item("Upgrade_Enable", "Provisioning/Firmware_Upgrade", "No");
                    else
                    {
                        $config .= $this->make_config_item("Upgrade_Enable", "Provisioning/Firmware_Upgrade", "Yes");
                        $config .= $this->make_config_item("Upgrade_Rule", "Provisioning/Firmware_Upgrade", "(\$SWVER ne ".$model_spa->getModelType()->getModelFirmware()->getVersion().")? ".Principio_Model_SettingMapper::getProfileRuleFirmware()->getValue());
                    };

                    // 3. Type Templates
                    $config .= $this->addTemplates($model_spa->getModelType());

                    // 4. Company Templates
                    $config .= $this->addCompanyTemplates($model_spa, $model_spa->getModelCompany());

                    // 4.1 VLAN & VLAN PC
                    if ($model_spa->getModelCompany()->getVlanID() != -1)
                    {
                        $config .= $this->make_config_item("Enable_VLAN", "System/VLAN_Settings", "Yes");
                        $config .= $this->make_config_item("VLAN_ID", "System/VLAN_Settings", $model_spa->getModelCompany()->getVlanID());

                        if ($model_spa->getModelCompany()->getVlanPcID() != -1)
                        {
                            $config .= $this->make_config_item("Enable_PC_Port_VLAN_Tagging", "System/VLAN_Settings", "Yes");
                            $config .= $this->make_config_item("PC_Port_VLAN_ID", "System/VLAN_Settings", $model_spa->getModelCompany()->getVlanPcID());
                        }
                        else
                            $config .= $this->make_config_item("Enable_PC_Port_VLAN_Tagging", "System/VLAN_Settings", "No");
                    }
                    else
                    {
                        $config .= $this->make_config_item("Enable_VLAN", "System/VLAN_Settings", "No");
                        $config .= $this->make_config_item("Enable_PC_Port_VLAN_Tagging", "System/VLAN_Settings", "No");
                    };


                    // 5. TypeInCompany Templates
                    $config .= $this->addTemplates($model_spa->getModelTypeInCompany());

                    // 6. SPA Templates
                    $config .= $this->addTemplates($model_spa);

                    // 7. Accounts
                    foreach ($model_spa->getAccountLinkCollection() as $model_account_link)
                    {
                        if ($model_account_link->getModelAccount()->getID() != -1)
                        {
                            $config .= $this->make_config_item("Display_Name_".$model_account_link->getExtNumber()."_", "Ext_".$model_account_link->getExtNumber()."/Subscriber_Information", $model_account_link->getModelAccount()->getDisplayName());
                            $config .= $this->make_config_item("Short_Name_".$model_account_link->getExtNumber()."_", "Phone/Line_Key_".$model_account_link->getExtNumber(), $model_account_link->getModelAccount()->getShortName());
                            $config .= $this->make_config_item("User_ID_".$model_account_link->getExtNumber()."_", "Ext_".$model_account_link->getExtNumber()."/Subscriber_Information", $model_account_link->getModelAccount()->getLogin());
                            $config .= $this->make_config_item("Password_".$model_account_link->getExtNumber()."_", "Ext_".$model_account_link->getExtNumber()."/Subscriber_Information", $model_account_link->getModelAccount()->getPassword());

                            $config .= $this->make_config_item("Proxy_".$model_account_link->getExtNumber()."_", "Ext_".$model_account_link->getExtNumber()."/Proxy_and_Registration", $model_account_link->getModelAccount()->getModelCompany()->getProxy());
                        };
                    };

                    $config .= "</flat-profile>\n";
                    $xml_parser = xml_parser_create("UTF-8");
                    xml_set_element_handler($xml_parser, "self::start_element", "self::end_element");
                    xml_set_character_data_handler($xml_parser, "self::string_element");
                    xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0);


                    if (!xml_parse($xml_parser, $config, true))
                    {
                        if ($opa_test)
                        {
                            $this->view->res_config .= "\nXML Error: ".xml_error_string(xml_get_error_code($xml_parser));
                            $this->view->res_config .= "\nat line ".xml_get_current_line_number($xml_parser);
                            $this->view->res_config .= "\n\nConfig is:\n\n".$config;
                        }
                        else
                            Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_XML_FAIL);
                    }
                    else
                    {
                        $this->expand_config();

                        if (!$opa_test)
                            Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_OK);
                    };

                    xml_parser_free($xml_parser);
                break; // case 1: Main Profile

                case 2: // Firmware
                    if ($model_spa->getModelType()->getModelFirmware()->getID() == -1)
                    {
                        if ($opa_test)
                            echo "This type doesn't use firmware.";
                        else
                        {
                            Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_FIRMWARE_NOT_USED);
                            header($_SERVER['SERVER_PROTOCOL']." 406 Not Acceptable");
                        };
                    }
                    else
                    {
                        if ($opa_test)
                            echo "Requested Firmware : [".$model_spa->getModelType()->getModelFirmware()->getFileName()."]\n";
                        else
                        {
                            // Disabling cache
                            header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
                            header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
                            Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_FIRMWARE_LOOKUP);
                        };

                        if (!($fw = @file_get_contents(APPLICATION_PATH."/../library/Principio/SPA/linksys/firmwares/".$model_spa->getModelType()->getModelFirmware()->getFileName())))
                        {
                            if (!$opa_test)
                            {
                                Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_FIRMWARE_FAIL);
                                header($_SERVER['SERVER_PROTOCOL']." 500 Internal Server Error");
                            }
                            else
                                echo "Failed: No such file";
                        }
                        else
                        {
                            if ($opa_test)
                                echo "Ok: File Found";
                            else
                            {
                                Principio_Model_SpaMapper::logProvisioning($model_spa, Principio_Model_SpaMapper::PRV_FIRMWARE_OK);
                                header("Content-Type: application/octet-stream");
                                header("Content-Disposition: attachment; filename=\"".$model_spa->getModelType()->getModelFirmware()->getFileName()."\"");
                                echo $fw;
                            };
                        };
                    };
                break;
            };
        }


        function expand_config ()
        {
            $this->view->res_config .= "<flat-profile>\n";
            foreach (self::$config_array as $key => $value)
            {
                if ($key != "flat-profile")
                {
                    $this->view->res_config .= "<".$key;
                    foreach ($value as $akey => $avalue)
                    {
                        if ($akey == "attribute_value")
                        {
                            $this->view->res_config .= ">";
                            if (strlen($avalue) > 0)
                                $this->view->res_config .= $avalue;
                        }
                        else
                            $this->view->res_config .= " ".$akey."=\"".$avalue."\"";
                    };
                    $this->view->res_config .= "</".$key.">\n";
                };
            };
            $this->view->res_config .= "</flat-profile>\n";
        }

        private function _validate($passed, $msg)
        {
            if (!$passed)
            {
                $this->view->res_config .= $msg;
                return false;
            }
            else
                return true;
        }


        public function indexAction()
        {
            $post_data = $this->getRequest()->getQuery();
            $this->view->res_config = "";

            // Checking parameters
            if (!$this->_validate(isset($post_data['s']), "Missed [s] parameter"))
                return;

            if (!$this->_validate(isset($post_data['s_id']), "Missed [s_id] parameter"))
                return;

            if (!$this->_validate(isset($post_data['mac']), "Missed [MAC] parameter"))
                return;

            if (!$this->_validate(isset($post_data['ip']), "Missed [IP] parameter"))
                return;


            $MAC = $post_data['mac'];
            $serial = $post_data['s_id'];
            $IP = $post_data['ip'];
            $stage = intval($post_data['s']);

            // Validating parameters
            if (!$this->_validate((($stage == 0) || ($stage == 1) || ($stage == 2) || ($stage == 9)), "Wrong stage"))
                return;

            if ($stage != 9)
            {
                if (!$this->_validate(strlen($MAC) == 12, "MAC len is incorrect"))
                    return;

                // Add ':' to MAC
                $new_mac = $MAC[0];
                for ($i = 1; $i < 12; $i++)
                {
                    if ($i % 2 == 0)
                    $new_mac .= ':';

                    $new_mac .= $MAC[$i];
                };
                $MAC = $new_mac;
            };


            if (($model_spa = Principio_Model_SpaMapper::fetchForPrv($IP, $MAC, $serial)) === false)
            {
                $this->view->res_config .= "No such SPA device";
                return;
            };

            self::$config_array = array();
            self::$config_item_value = "";
            self::$config_last_item = "";

            switch ($stage)
            {
                case 0:
                break;

                case 1: // Profile
                    $this->gen_config($model_spa, 1, false);
                break;

                case 2: // Firmware Download
                    $this->gen_config($model_spa, 2, false);
                break;


                case 9: // Test from Principio
                    $this->view->res_config .= "Stage 1: Main Profile\n\n";
                    $this->gen_config($model_spa, 1, true);
                    $this->view->res_config .= "\n\nStage 2: Firmware\n\n";
                    $this->gen_config($model_spa, 2, true);
                break;

            };
        }
    }
?>